#pragma once

#include "bezier.h"
#include "controls.h"

namespace outline {

//bezier_guide is optimizer version of reverse_build algorithm from bezier_build.h

//value of this vector represents, in which segment of countor [i,i+1] lies each pole
typedef unsigned bpoint;
typedef std::vector<unsigned> bpoint_vector;

/// given position of a point on a (bezier) curve and derivative at this point,
/// moves the pole (the place where the point should be pulled to) along the polyline piece [begin, end);
/// returns true if the pole was moved to another node or segment (that is significant change was made, and another iteration may be required)
template <typename T, typename R>
bool move_pole_near(bpoint & b, point<R> & pole,
	std::vector< point<T> > const & nodes, uint begin, uint end,
	point<R> const & pos, point<R> const & deriv);

///\return discrepancy of fitting
template <typename T, typename R>
R bezier_guide(
	//input nodes of polyline
	std::vector< point<T> > const & nodes,
	uint begin, uint end, ///< range from nodes
	//parameters
	uint max_iterations,
	R stop_mean_discrepancy,
	R oversample_factor, ///< the ratio between the counts of fitted points on bezier and polyline nodes
	bool controls_initialized,
	bool poles_initialized, ///< and bvec_initialized in the same time
	//out
	bezier<R> & controls,
	std::vector< point<R> > & poles,
	bpoint_vector & bvec
);

///\return discrepancy of fitting
template <typename T, typename R>
inline R bezier_guide(
   //input nodes of polyline
   std::vector< point<T> > const & nodes,
   uint begin, uint end, ///< range from nodes
   //parameters
   uint max_iterations,
   R stop_mean_discrepancy,
   R oversample_factor, ///< the ratio between the counts of fitted points on bezier and polyline nodes
   bool controls_initialized,
   //out
   bezier<R> & controls
)
{
	std::vector< point<R> > poles;
	bpoint_vector bvec;
	return bezier_guide(nodes, begin, end, 
		max_iterations, stop_mean_discrepancy, oversample_factor, 
		controls_initialized, false,
		controls, poles, bvec);
}

template <typename T, typename R = typename type_traits<T>::real_type>
class incremental_bezier_guide : public typedefs<T, R>
{
public:
	uint max_iterations;
	R stop_mean_discrepancy;
	R oversample_factor;
public:
	incremental_bezier_guide() : nodes_(0) { }
	void clear() { 
		nodes_ = 0; 
		poles.clear();
		bvec.clear();
	}
	R initial_fit(nodes_type const & nodes, uint begin, uint end);
	bool initialized() const
		{ return nodes_ != 0; }
	R incremental_fit(uint end);
	R fit(nodes_type const & nodes, uint begin, uint end) {
		if (initialized() && end == end_+1) {
			assert(nodes_ == &nodes);
			assert(begin == begin_);
			return incremental_fit(end);
		}
		else
			return initial_fit(nodes, begin, end);
	}
public:
	bezier_type b;
private:
	real_point_vector_type poles;
	bpoint_vector bvec;
	nodes_type const * nodes_;
	uint begin_;
	uint end_;
};

template <typename R>
inline uint bpoints_count(uint len, R oversample_factor) {
	assert (len >= 4);
	return 5 + (len-4) * oversample_factor; //4 points may be fittes with zero discrepancy, therefore we need more than 5
} 

} //namespace outline
